const { ipcMain } = require('electron');
const path = require('path');
// const log = require("../utils/log")
const { enumDownloadState } = require("../../utils/utls")
const fs = require("fs")
const { Throttle } = require('stream-throttle');
const {
  saveBlocker,
  stopSystemActive
} = require("../utils/systemSetting")
const {
  fileSavePath,
  download,
  addDownloadItem,
  updateDownloadItem,
  doneDownloadItem,
  setDownloadStore,
  getDownloadStore,
  pauseOrResumeFn,
  removeDownloadDataFn,
  getDownloadItem,
  initDownloadData,
  removeProjectData,
  updateAllProgress,
  saveData,
  saveInterruptData
} = require('../downLoad/fileUtils')
const {
  openFile,
  openFileInFolder,
} = require('../../utils/utls')
const { classHelperByte } = require("../../utils/string")
const store = require("../../electronStore/index")
let win = null
let savePath = "" // 保存路径
let downLoadingList = [] // 正在下载的数据
let dataList = [] // 返回给前端的下载列表
let maxDownloadNum = 3 // 下载并发数量
let throttleRate = null // 文件下载速度
let downLoadComplateList = [] // 下载完成的数据
const options = {
  headers: {
    'User-Agent': "electron/kingshine"
  },
  httpsRequestOptions: {},
  removeOnFail: false, // 失败时是否删除文件
  removeOnStop: true, // 停止时是否删除文件
  resumeIfFileExists: false, // 如果文件没有完成将恢复下载
  // forceResume: false, // 禁用断点续传
  // override: true, // 覆盖已存在的文件
  // resumeOnIncomplete: false, // 如果文件不完整，则继续下载(如果使用任何修改文件的管道，则设置为false)
}
/** ok
 * 下载文件
 * @param item 下载项
 */
async function downloadFile(dataList1) {
  try {
    let dialogPath
    if (dataList1.isReDownload) { // 断点下载
      dialogPath = dataList1.savePath
      savePath = dataList1.filePath
      setDlConfig(1)
    } else { // 下载
      // 1. 打开对话框获取路径; 2.设置下载配置
      dialogPath = await setDlConfig(0)
      if (!dialogPath) return false
      // 给每个下载项添加项目文件夹
      savePath = path.join(dialogPath, dataList1.fileName.replaceAll(/\/+|\\+/g, '_'))
    }

    // 初始化数据结构
    const downloadData = initDownloadData(dataList1, savePath, dialogPath)
    // 添加下载项
    const index = dataList.findIndex(item => item.projectJobId === downloadData.projectJobId)
    if (index !== -1) {
      const urls = dataList[index].children.map(item => item.url)
      dataList[index].children.push(...downloadData.children.filter(item => !urls.includes(item.url)))
    } else {
      dataList.push(downloadData)
    }
    // 下载文件
    interDownload()
    // 下载文件时，保持系统活跃状态
    saveBlocker()
    return true
  } catch (error) {
    // log.main.error(error)
    return false
  }
}
/**
 * 设置下载的并行任务和速度
 * @param {Number} type 1断点 0下载
 */
async function setDlConfig(type) {
  const { downloadconcount, dlIsLimit, downloadtransrate, downloadPath } = store.get("configOption")
  // 下载最大并行数
  maxDownloadNum = downloadconcount
  // 下载速度
  throttleRate = dlIsLimit ? classHelperByte(downloadtransrate + 'kB') : null
  if(type) return
  // 下载位置
  const path = await fileSavePath(win, downloadPath)
  return path
}
/** ok
 * 并发下载
 */
function interDownload() {
  // 提取所有子元素
  const list = dataList.flatMap(item => item.children || []);
  let index = 0;

  // 循环下载，直到达到最大下载数或遍历完所有子元素
  while (downLoadingList.length < maxDownloadNum && index < list.length) {
    const currentChild = list[index];

    // 检查是否已在下载队列中
    if (!downLoadingList.some(item => item.url === currentChild.url)) {
      const parentObj = dataList.find(parent => parent.children.includes(currentChild));
      const dl = download(currentChild, savePath, options);

      downLoadingList.push({ dl, url: currentChild.url });

      // 处理下载事件
      download_Event(dl, currentChild, parentObj);
    }

    index++;
  }

  // 如果没有正在下载的内容，则停止系统活跃状态
  if (downLoadingList.length === 0) stopSystemActive();
}

/** ok
 * 刚开始下载时获取信息
 * @param dl 下载实例对象
 * @param downloadItem 下载数据
 * @param parentObj 下载数据的父项目数据
 */
function download_Event(dl, downloadItem, parentObj) {

  dl.on('download', (downloadInfo) => {
    const rate = Number(throttleRate)
    if (rate > 0) {
      const throttle = new Throttle({ rate })
      // 将下载的数据通过 throttle 进行速度控制后写入文件
      dl.pipe(throttle)
    }
    addDownloadItem(downloadInfo, downloadItem, dl)
    sendDataListUpdate()
  })

  dl.on('error', (err) => {
    // log.error.error('下载发生错误：', downloadItem.url, err)
    // log.error.error('错误信息：', err.message, '错误状态：', err.status, '错误数据体：', err.body)
    downloadItem.errMsg = err.message
    delSaveData(downloadItem)
  });
  
  // 从上一个文件路径继续下载
  if (downloadItem.isReDownload) {
    const isHave = fs.existsSync(downloadItem.filePath)
    if (isHave) {
      const state = {
        filePath: downloadItem.filePath,
        fileName: downloadItem.fileName,
        downloaded: fs.statSync(downloadItem.filePath).size,
        // total: downloadItem.total
      }

      dl.__headers.range = `bytes=${state.downloaded}-`
      dl.resumeFromFile(downloadItem.filePath).catch(err => {
        // log.error.error('下载错误', downloadItem.url, err, 'dsadsas:::', err.message)
        // delSaveData(downloadItem)
      });
    } else {
      dl.__headers.range = 'bytes=0-'
      dl.start().catch(err => {
        // log.error.error('下载错误', downloadItem.url, err, 'dsadsasd', err.message)
        // delSaveData(downloadItem)
      });
    }
  } else { // 开始下载
    dl.__headers.range = 'bytes=0-'
    dl.start().catch(err => {
      // log.error.error('下载错误', downloadItem.url, err, 'hhahah:::', err.message)
      // delSaveData(downloadItem)
    });
  }

  // 更新每秒下载进度
  dl.on('progress.throttled', stats => {
    // 更新下载项
    updateDownloadItem(downloadItem, parentObj, stats)
    // 更新下载总进度
    win.webContents.send('downloadAllProgress', updateAllProgress(dataList))
    // 向前端发送更新项
    sendDownloadUpdate(downloadItem, parentObj)
  });

  // 暂停
  dl.on('pause', (e) => {
    console.log('暂停:', e)
  })

  // 恢复
  dl.on('resume', (isResume) => {
    console.log('恢复:', isResume)
  })

  // 状态更改时
  dl.on('stateChanged', (state) => {
    console.log('状态更改时:', state)
    downloadItem.state = enumDownloadState(state)
    parentObj.state = parentObj.children.some(item => item.state === 2) ? 2 : 3
    // 向前端发送更新项
    sendDownloadUpdate(downloadItem, parentObj)
  })

  // 下载完成后处理文件
  dl.on('end', (downloadInfo) => {
    delSaveData(downloadItem);
  });

  // 停止下载
  dl.on('stop', () => {
    doneDownloadItem(downloadItem.url, downLoadingList, dataList)
    sendDataListUpdate()
    interDownload()
  })

  // 发生非故意抛出错误时
  dl.on('warning', (err) => {
    // log.error.error('发生非故意抛出错误时', downloadItem, err, "msg:::", err.message)
    // delSaveData(downloadItem)
  })

  // 当底层套接字因不活动而超时时
  dl.on('timeout', (err) => {
    // log.error.error('超时', downloadItem, err)
    // delSaveData(downloadItem)
  })

}

/** ok
 * 发送更新的下载项而不是整个列表
 * @param downloadItem - 下载项
 * @param parentObj - 下载项的父级项目
 */
function sendDownloadUpdate(downloadItem, parentObj) {
  win.webContents.send('download-info', JSON.stringify({ downloadItem, parentObj }));
}
/**
 * 发送全部数据
 */
function sendDataListUpdate() {
  win.webContents.send('sendDataList', JSON.stringify(dataList));
}
/**
 * 删除保存数据
 * @param {*} downloadItem 下载项
 */
function delSaveData(downloadItem) {
  let obj = doneDownloadItem(downloadItem.url, downLoadingList, dataList)
  saveData(obj, downLoadComplateList, win)
  sendDataListUpdate()
  interDownload()
}
/** ok
 * 暂停或恢复
 * @param downloadItem - 下载项
 */
const pauseOrResume = (downloadItem) => {
  if (downloadItem.children) { // 批量
    const children = downloadItem.children
    for (let i = 0; i < children.length; i++) {
      pauseOrResumeFn(children[i], downLoadingList, dataList, downloadItem)
    }
  } else { // 单个
    pauseOrResumeFn(downloadItem, downLoadingList, dataList)
  }
  return downloadItem
}

/** ok
 * 移除下载项。下载中会取消下载
 * @param downloadItem - 下载项
 */
const removeDownloadItem = (downloadItem) => {
  // 删除项目以及项目下所有文件
  if (downloadItem.children) {
    // 1. 首先删除 dataList 中的数据,防止先取消后,又从 dataList 本应该删除的数据中自动填空下载
    removeProjectData(downloadItem, dataList)
    const children = downloadItem.children

    // 2. 删除正在下载的文件,不需要删除 downLoading 中的数据, 因为停止了下载, 会进入 stop 事件中删除
    const urls = children.map(obj => obj.url)
    const dlList = downLoadingList.map(item => {
      if (urls.includes(item.url)) {
        return item.dl
      }
    }).filter(Boolean)
    dlList.map(dl => {
      dl.stop()
      dl = null
    })
  } else { // 删除单个文件
    removeDownloadDataFn(downloadItem, downLoadingList, dataList)
  }
  interDownload()
  // 3. 返回前端最新数据
  sendDataListUpdate()
  return true
}

/** ok
 * 全部暂停下载
 */
const pauseAllDownload = () => {
  downLoadingList.forEach(item => {
    const dl = getDownloadItem(downLoadingList, item.url)
    if (!dl) return
    dl.pause()
  })
  // 返回前端最新数据
  sendDataListUpdate()
}

/** ok
 * 全部开始下载
 */
const beginAllDownload = () => {
  downLoadingList.forEach(item => {
    const dl = getDownloadItem(downLoadingList, item.url)
    if (!dl) return
    dl.resume()
  })
  // 3. 返回前端最新数据
  sendDataListUpdate()
}

/** ok
 * 全部取消下载
 */
const removeAllDownload = () => {
  // 1. 清空数据(必须先清空，否则没有下载的文件不会被删)
  dataList = []; // 返回给前端的下载列表

  // 2. 取消下载并从downLoadingList中移除
  let dlList = downLoadingList.map(item => {
    return item.dl
  }).filter(Boolean)
  dlList.forEach(dl => {
    dl.stop()
    dl = null
  })
}

/** ok
 * 重新下载后重新设置传输完成列表(筛掉重新下载项)
 * @param params
 */
const setTransferCompleteList = (params) => {
  downLoadComplateList = getDownloadStore() || []

  // 1. 删除重新下载项
  const reParentObj = downLoadComplateList.find(item => params.projectJobId === item.projectJobId)
  const urls = params.children.map(item => item.url)
  const indexs = reParentObj.children.map((item, index) => {
    if (urls.includes(item.url)) return index
    return null
  }).filter(item => item !== null)
  reParentObj.children = reParentObj.children.filter((item, index) => !indexs.includes(index))
  // 2. 如果没有下载项则清空
  const index = downLoadComplateList.findIndex(item => item.children.length === 0)
  if (index !== -1) downLoadComplateList.splice(index, 1)
  // 3. 更新下载列表
  setDownloadStore(downLoadComplateList)
  return true
}

/** ok
 * 清空传输完成列表
 */
const clearTransferCompleteList = () => {
  downLoadComplateList = []
  setDownloadStore(downLoadComplateList)
}

/**
 * 刚打开程序检查是否有需要下载项
 */
const readyDownloads = () => {
  downLoadComplateList = getDownloadStore() || []
  // 检查是否有未完成下载项
  const stateList = downLoadComplateList.flatMap(item => item.children)
  if (stateList.length === 0) return false
  const isCanDownload = stateList.some(item => item.state !== 4)
  return isCanDownload
}

/**
 * 刚打开程序开始下载文件
 */
const readyDownloading = () => {
  // 组织下载项，将完成列表的下载项删除掉
  const dlParentList = downLoadComplateList.filter(item => {
    if (item.children && item.children.length) {
      return item.children.some(it => it.state !== 4)
    }
    return false
  }).filter(Boolean)
  const arr = dlParentList.map(parent => {
    const parentObj = {
      fileName: parent.fileName,
      projectJobId: parent.projectJobId,
      savePath: parent.savePath,
      filePath: parent.filePath,
      isReDownload: true,
      children: []
    }
    parentObj.children = parent.children.map(item => {
      if (item.state === 4) return false
      return {
        id: item.id,
        url: item.url,
        fileName: item.fileName,
        fileSize: item.fileSize,
        projectJobId: item.projectJobId,
        isReDownload: true, // 代表这是断点下载的数据
        filePath: item.filePath,
        total: item.total
      }
    }).filter(Boolean)
    return parentObj
  })
  for (const iterator of arr) {
    setTransferCompleteList(iterator)
    downloadFile(iterator)
  }
  return true
}

/**
 * 程序关闭, 保存正在下载项
 */
const execAppDownloads = () => {
  downLoadingList.forEach(item => item.dl.pause())
  ipcMain.removeAllListeners() // 移除所有监听器，不移除会出错 'Object has been distryed', 表示窗口被销毁但是再次访问了被销毁的窗口对象导致
  saveInterruptData(dataList, downLoadComplateList)
}

/**
 * 添加主进程 ipc 调用事件
 */
const listenerEvent = (win1) => {
  win = win1

  // 新建下载
  ipcMain.handle('downLoadFile', (event, data) => downloadFile(data))

  // 暂停或恢复下载
  ipcMain.handle('pauseOrResume', (event, downloadItem) => pauseOrResume(JSON.parse(downloadItem)))

  // 删除下载项
  ipcMain.handle('download-cancel', (event, downloadItem) => removeDownloadItem(JSON.parse(downloadItem)))

  // 获取下载数据
  ipcMain.handle('getDownloadList', () => JSON.stringify(dataList))

  // 打开文件
  ipcMain.handle('openFile', (event, path) => openFile(path))

  // 打开文件所在路径
  ipcMain.handle('openFileInFolder', (event, path) => openFileInFolder(path))

  // 全部开始下载
  ipcMain.handle('beginAllDownload', () => beginAllDownload())

  // 全部暂停下载
  ipcMain.handle('pauseAllDownload', () => pauseAllDownload())

  // 全部取消下载
  ipcMain.handle('removeAllDownload', () => removeAllDownload())

  // 获取 token
  ipcMain.handle('getToken', (event, token) => options.headers.Token = token)

  // 程序刚打开, 检查是否有可下载项
  ipcMain.handle("readyDownloads", () => readyDownloads())

  // 刚打开程序开始下载
  ipcMain.handle("readyDownloading", () => readyDownloading())

}

module.exports = {
  setTransferCompleteList,
  listenerEvent,
  clearTransferCompleteList,
  execAppDownloads
}
